package com.cctc.juc.source.Athread.threadlocal;
/**
 * ThreadLocal [线程本地变量]
 * 【概述】 ThreadLocal 是 JDK 提供的线程本地变量类。Thread 类中定义了一个类型为 ThreadLocal.ThreadLocalMap 的 threadLocals 属性，每个线程都有一个自己的 ThreadLocalMap 引用。也就是说，如果我们创建了一个 ThreadLocal 变量，访问这个变量的每个线程都会有这个变量的一个本地副本。如果多个线程同时对这个变量进行读写操作时，实际上操作的是线程自己本地内存中的变量（本质上是同一个 ThreadLocalMap 实例中不同的 Entry 条目），从而避免了线程安全的问题。很多情况下，使用 ThreadLocal 比直接使用同步机制（如 synchronized）解决线程安全问题更简单，更方便，且结果程序拥有更高的并发性。本质上是属于以空间换时间的设计思路，该设计思路属于了另一种意义的 “无锁编程”。
 * 【核心接口】
 * - initialValue() 当 “线程本地变量” 在当前线程的 ThreadLocalMap 中尚未绑定值时，该方法用于获取初始值。
 * - set(T value) 设置当前线程的  ThreadLocalMap 实例中绑定的本地值。
 * - T get() 获得当前线程的 ThreadLocalMap 实例中绑定的本地值。
 * - remove() 移除当前线程的 ThreadLocalMap 实例中绑定的本地值。
 * [使用场景]
 * 1. 线程隔离，例如数据库 Session 连接独享。
 * 2. 跨函数数据传递，包括：
 * - 传递请求用户 ID、事务 ID；
 * - 传递请求用户 Session 会话信息；
 * - 传递 HTTP 请求实例 HttpRequest；
 * - 其他需要在函数之间传递的数据等。
 * 【ThreadLocal 优化】
 * 1. JDK 8 以前：ThreadLocal.ThreadLocalMap 为每个线程实例维护了一个 Entry<Thread, LocalVariables> 元素，当线程数量过多时，导致 ThreadLocalMap（开放地址法，而 Map 为链地址法） 哈希冲突严重，触发扩容，影响性能；
 * 2. JDK 8 及其以后：每个线程 Thread 内部拥有一个 ThreadLocal.ThreadLocalMap 属性，如果我们给一个 Thread 创建多个 Threadlocal 实列，然后放置本地数据，那么当前线程的 ThreadLocalMap 中就会有多个 Entry<WeakReference<ThreadLocal<?>> 元素。由于每个线程所存储的本地变量一般都比较少，使得 Entry<WeakReference<ThreadLocal<?>>, LocalVariable> 元素个数较少，不再导致 ThreadLocalMap 哈希冲突，提升了性能。此外，当每个线程实例被销毁时，其内部拥有的 ThreadLocalMap 也会随之被销毁，在一定程度上减少了内存的消耗。
 * 3. Netty 中，为了进一步提升性能：
 * - 性能开销，每个线程都会持有一个 ThreadLocal.ThreadLocalMap 变量副本，创建和销毁这些变量会带来额外的性能开销。
 * - 内存占用，每个线程都会持有一个 ThreadLocal.ThreadLocalMap 变量副本，这可能导致大量的内存占用问题。
 * Netty 提供的 FastThreadLocal 主要依赖于两个重要的类：FastThreadLocalThread 和 InternalThreadLocalMap。
 * 1）FastThreadLocalThread 类。该类继承自 Thread 原生了，并提供了一个扩展字段 InternalThreadLocalMap，用于替换 ThreadLocalMap，来存储线程本地变量数据。
 * 2）InternalThreadLocalMap 类。该类与 ThreadLocalMap 一样，都是用于存储线程本地变量数据，但是 InternalThreadLocalMap 直接使用 Object Set 数组代替了 Entry Map 数组，并为每个线程本地变量分配一个全局唯一索引 index，在读写数据时直接通过 index（数组下标）操作线程本地变量，时间复杂度为 O(1)。
 * 因此，只有 FastThreadLocal 和 FastThreadLocalThread 组合使用时，才能发挥出 FastThreadLocal 的性能优势。
 * 面试题：和 ThreadLocal 相比，FastThreadLocal 的优势有哪些？？？
 * 1）节省性能开销和内存占用。通过内存池化 FastThreadLocal 线程局部变量实例，避免创建和销毁这些变量带来的性能开销和内存占用问题。
 * 2）提高访问性能和扩容效率。
 * - FastThreadLocal 可以直接根据数组下标 index 访问线程本地变量，时间复杂度为 O(1)；而 ThreadLocal 在数据较多时很容易发生哈希冲突，且 ThreadLocalMap 内部采用的是线性探测法（开放地址法）解决哈希冲突的，需要不停的向下寻找空闲位置，效率较低。
 * - FastThreadLocal 相比 ThreadLocal 扩容更加简单、高效。FastThreadLocal 以数组小标 index 为基准向上取整到 2 的次幂作为扩容容量，然后只需把原数据拷贝到新数组即可；而 ThreadLocal 内部采用的哈希表，所以在扩容时需要再做一轮 rehash，实现复杂且效率较低。
 * 【ThreadLocal 内存泄露问题（不再用到的内存 [Key 和 Value]，没有及时释放）】
 * - <Key 内存回收> 由于 ThreadLocalMap 中 Entry 的 Key 使用了弱引用，在下次 GC 发生时，就可以使那些没有被其他任何运行（方法栈帧）工作线程（强引用）指向、仅被 Entry 的 Key 所（弱引用）指向的 ThreadLocal 实例能被顺利回收。
 * - <Value 内存回收> 在 ThreadLocal 被回收之后，其 Entry 的 Key 值变为 null。
 * --> 1. 探测式回收。后续只要存在一个针对任何 ThreadLocal 的 get() 、 set() 或 remove() 操作时，ThreadLocalMap 的内部代码会清除这些 Key 为 null 的 Entry 元素，完成相应 Value 内存的释放。
 * --> 2. 启发式（并不是每次操作都进行，而是基于一定的条件和概率）回收。在 ThreadLocalMap 的 set() 方法中，有一个阈值（默认为 ThreadLocalMap.Entry 数组长度的 1/4），当执行完探测式回收后，剩余的 Entry 数量大于这个阈值时，就会触发一次启发式清理操作（执行 do-while 循环检查清理过期 key，结束条件是连续 n 次未发现过期 key 就结束循环）。
 * --> 3. 主动调用 remove() 方法手动回收。在使用线程池的场景中，因为线程池中的线程通常是长期存在的，它们的 ThreadLocal 变量也不会自动清理，很有可能导致内存泄漏。因此，在我们使用完 ThreadLocal 后显式调用 remove()方法，以确保不再需要的值能够被及时回收，key 和 value 都同时清理，一锅端，这样可以避免潜在的内存泄漏问题，并减少垃圾回收的压力。
 * 【ThreadLocal 编程规范（节省性能开销）】
 * 1）ThreadLocal 实例作为 ThreadLocalMap 的 Key，针对一个线程内所有操作是共享的，所以建议设置 static 饰符，以便被所有的对象共享，节省内存空间；
 * 2）为了确保 ThreadLocal 实例的全局唯一性，还应该使用 final 进行加强修饰，以防止其在使用过程中发生动态变更；
 * 3）还有，为了缩小使用的范围，尽可能不让他人引用，还应该使用 private 进行修饰；
 * 4）最后，一旦使用了 static、final 进行修饰，ThreadLocal 将变为类的全局共享常量，从而导致 Key（堆内存强引用） 所在的 Entry 不会被自动清空，同时也会让 Entry 中的 Value 指向的对象一直存在强引用，不会被释放，最终导致内存泄漏（不再用到的内存 [Key 和 Value]，没有及时释放）。所以，在使用完 static、final 修饰 ThreadLocal 实例后，必须使用 remove() 进行手动释放。如果使用的是线程池，可以定制线程池的 afterExecute 方法（任务执行完成之后的钩子方法），在任务执行完成之后，调用 TheadLocal 实例的 remove（）方法，从而实现的其线程内部的 Entry 得到释放。
 * 【ThreadLocal & FastThreadLocal 缺点】
 * 问题：在线程池【复用】线程中使用 ThreadLocal 变量可能导致数据混乱，因为多个任务有可能【复用】同一个，它们共享了同一个线程的 ThreadLocal。如果使用 ThreadLocal 存储数据，可能会导致数据被错误地共享。
 * 解决办法：在线程池【复用】线程中执行的任务开始前和结束后，重写线程池的 beforeExecute() 或 afterExecute() 方法，显式地清理【复用】线程的 ThreadLocal 变量，确保每个任务都能在使用完【复用】线程的 ThreadLocal 之后进行清理。
 * 【ThreadLocal 实现线程间通信】
 * 1. InheritableThreadLocal [ITL 可继承的线程本地变量]
 * 描述信息：ITL 是 TL 派生出来专门解决线程本地变量父传子问题的。当一个线程派生出一个子线程时，子线程可以继承父线程中的值，这在某些情况下特别有用，比如在进行请求处理或任务分派时。
 * 缺点：
 * 1） 线程不安全。当一个线程派生出一个子线程时，子线程可以继承父线程中的值。子线程继承过来的 ThreadLocalMap 变量与父线程的 ThreadLocalMap 指向的是同一个对象，如果该 ThreadLocalMap 是只读的，没有问题，但是如果是可写的，那么任意子线程针对该 ThreadLocalMap 的修改都会影响到父线程的 ThreadLocalMap，从而引发线程安全问题。
 * 2） 无法应用于线程池中的 【复用】 线程。对于线程池等池化 【复用】 线程执行组件来说，ITL 将会失效，因为 ThreadLocalMap 是通过在派生子线程的时候进行向下传递的，而线程池在执行异步任务时可能不再需要创建新的线程了，因此也就不会再调用初始化方法传递父线程的 ThreadLocalMap 给子线程了。
 * 解决方案：TransmittableThreadLocal  [TTL 可传播的线程本地变量（ITL 的优化版）] 解决了这个问题，它可以在多线程环境下正确地传递数据。当一个线程从线程池中获取到一个线程时，TTL 会自动将当前线程的 ThreadLocal【副本】传递给【复用】线程，从而保证数据的正确性。
 * 2. TransmittableThreadLocal [TTL 可传播的线程本地变量（ITL 的优化版）]
 * 描述信息： TransmittableThreadLocal 是阿里巴巴开源的一个线程本地变量，它是 InheritableThreadLocal 的一个增强版，可以在线程池、ForkJoinPool 等多线程环境下使用，解决了 InheritableThreadLocal 在多线程环境下的数据传递问题。
 * 1）TTL 继承自 ITL, 具体值仍然保存在线程内部的 inheritableThreadLocals，不涉及线程池时可以当成 InheritableThreadLocal 使用;
 * 2）通过一个 Holder，可以找到 JVM 进程中每个线程当前所持有的 ThreadLocal 对象;
 * - Holder 的类型为  WeakHashMap<TransmittableThreadLocal<Object>, ?>，可以把它被当成一个 Set 使用（Value 永远为 null，用不到），存放的是所有和当前线程产生关联的 TTL，通过它可以找到 JVM 进程中每个线程当前所持有的 ThreadLocal 对象（即使用 WeakHashMap 收集线程中所有的 TTL）。
 * 3）单纯的使用 TTL 是达不到支持线程池本地变量的传递的，还需要使用 TtlRunnable 的 get 方法来包裹一个 Runnable 对象，包裹对象时，通过 Holder，捕获 [captureAllTtlValues()] 父线程当前持有的所有 ThreadLocal。随后，子线程启动，在 Runnable 对象执行 run 方法之前 [beforeExecute()]，从 Holder 中取出 [replayCapturedTtlValue()] 先前捕获到的父线程所持有的 ThreadLocal 对象，并设置 [useValueInTtl()] 到当前子线程当中，设置之前会保存子线程原有的 ThreadLocal 作为 BackUp，当子线程执行结束后，通过 BackUp 恢复 [restoreTtlValueBeforeReplay()] 其原有的ThreadLocal。
 * 应用场景：以线程（本地）安全的方式保存线程上下文信息，以便在任意需要的地方进行获取，从而避免线程（同步）安全带来的性能损耗。
 * 1）分布式链路跟踪系统 或 全链路压测（即链路打标）；
 * 2）日志收集记录系统上下文信息；
 * 3）Session 级 Cache；
 * 4）应用容器或上层框架跨应用代码给下层 SDK 传递信息等。
 * 【总结】
 * ThreadLocal 实例通常作为类中的私有静态属性，这些属性希望将自身的状态（例如，用户 ID 、事务 ID、用户 Session、HTTP 请求、数据库连接等）与每一个工作线程相关联。使用 ThreadLocal 是解决多线程数据安全问题的一种比较好的解决方案，它通过为每个线程提供一个独立的本地副本，去解决并发访问的冲突问题。很多情况下，使用 ThreadLocal 比直接使用同步机制（如 synchronized）解决线程安全问题更简单，更方便，且结果程序拥有更高的并发性。本质上是属于以空间换时间的设计思路，该设计思路属于了另一种意义的 “无锁编程”。
 * 【面试题】
 * 1. 请解释 ThreadLocal 是什么，以及它的主要用途是什么？
 * 2. ThreadLocal 的内部机制是怎样的？请解释一下 ThreadLocalMap 和 Entry。
 * 3. 使用 ThreadLocal 是否会导致内存泄漏？如果是，如何避免？
 * 4. 在使用线程池时，ThreadLocal 可能会出现什么问题？如何解决？
 * 5. 在父子线程间如何共享数据？ThreadLocal 能实现吗？如果不能，那应如何实现？
 * 6. 能否解释一下 TransmittableThreadLocal 与 InheritableThreadLocal 的区别和联系？
 * 【参考文档】
 * - https://blog.csdn.net/Mrxiao_bo/article/details/136208633
 * - ... ...
 */